package Master;
/**
 * Project:    metsysdirg
 * File Name: Task.java
 * Change History:
 *     ********************************
 *     1.0     5/14/2011    Hengfeng Li
 *         Create the skeleton file
 *     ********************************
 *
 */

import Master.ScheduleAlgorithm.CompareFactor;
import Module.RegistryService;
import Module.StatusService;
import Module.WorkService;

import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.ArrayList;

/**
 * The Resource class stores the information of a remote worker
 */
public class Resource implements Comparable {
    private WorkService workService;
    private RegistryService registryService;
    private StatusService statusService;
    private ArrayList<Task> tasks;
    private int finishedJobs;

    public StatusService getStatusService() {
		return statusService;
	}

	private int ID;
    public int getID() {
		return ID;
	}

	private String hostName;

    private String password;
    private String authCode;

    private String address;
    private int portNo;

    // count in seconds
    private float nextCompleteTime;

    private WorkerDispatcher dispatcher;

    private int jobsCounter;

    /** The cost of one sec running time in worker */
    private float cost;
    private static String workServiceName = "WorkService";
    private static String statusServiceName = "StatusService";
    private static String registryServiceName = "RegistryService";

    private boolean isAvailable;
    private boolean isReschedule;


    public Resource(int ID, String hostName,
                    String address, int portNo, float cost
                    ,String password) throws Exception {
        this.ID = ID;
        this.hostName = hostName;
        this.address = address;
        this.portNo = portNo;
        this.cost = cost;
        this.finishedJobs = 0;
        this.password = password;
        System.out.println("resource id:"+ID+"password:"+password);

        nextCompleteTime = 0;

        jobsCounter = 0;

        tasks = new ArrayList<Task>();

        isAvailable = true;
        isReschedule = false;

        try{
            obtainServices(this.address,this.portNo);
        } catch (Exception ex){
            this.isAvailable = false;
           
            System.out.println("Resource is not available.");
            ex.printStackTrace();
            return;
        }

        //obtainServices(this.address,this.portNo);

        dispatcher = new WorkerDispatcher();
    }

    public void setAvailable(boolean isAvailable){
        this.isAvailable = isAvailable;
    }

    public void setReschedule(boolean isReschedule){
        this.isReschedule = isReschedule;
    }

    public boolean isAvailable(){
        return this.isAvailable;
    }

    public boolean isReschedule(){
        return this.isReschedule;
    }

    /* Clear the queue in resources */
    public void clearQueue(){
        //this.dispatcher.clearFinishedJobs();
        this.tasks.clear();
        clearFinshedJobs();
    }
    
    public void clearFinshedJobs(){
    	this.finishedJobs = 0;
    }
    
    public void incFinishedJobs(){
    	this.finishedJobs++;
    }

    public ArrayList<Task> getUnfinishedTasks(){

        System.out.println("FinishedJobs: " + finishedJobs);

        ArrayList<Task> unfinishedJobs = new ArrayList<Task>();

        for(Task task : tasks){
        	System.out.println("SSSSSSSSSSSSSSSSSSSSSSSSSSSSS resource ID :" + 
        			this.ID + "task ID: " +task.getTaskID());
        }
        System.out.println("Resource ID: " + this.getID() + "Task size: " + tasks.size());
        for(int i = finishedJobs; i < tasks.size(); i++){
        	System.out.println("Unfinished task ID ++++++++" + tasks.get(i).getTaskID());
            unfinishedJobs.add(tasks.get(i));
        }

        return unfinishedJobs;
    }


    public float getNextCompleteTime(){
        return nextCompleteTime;
    }

    public void runDispatcher(){
        dispatcher.start();
    }

    public void stopWorkerDispatcher(){
        dispatcher.stopRunning();
    }

    public void addTask(TaskRunnable task){
        nextCompleteTime += task.getEstimateTime();
        task.specifyResource(this);
        tasks.add((Task)task);
        dispatcher.add(task);
        this.jobsCounter++;
    }
    
    public void restartTask(Task task){
    	dispatcher.add(task);
    }

    private void obtainServices(String address, int port) throws Exception {
        // look up the registry for the selected service name
        // and obtain a proxy
        Registry registry = LocateRegistry.getRegistry(address, port);
        Object proxy = registry.lookup("rmi:" + workServiceName);

        // cast it back to the remote interface registered with
        // service name...


        this.workService = (WorkService)proxy;

        if(workService == null) {
            System.out.println("NULL!!!!!");
        }

        proxy = registry.lookup("rmi:" + registryServiceName);

        // cast it back to the remote interface registered with
        // service name...
        this.registryService = (RegistryService)proxy;

        proxy = registry.lookup("rmi:" + statusServiceName);

        // cast it back to the remote interface registered with
        // service name...
        this.statusService = (StatusService)proxy;
    }

    public WorkService getWorkService(){
        return workService;
    }

    public RegistryService getRegistryService(){
        return registryService;
    }

    public String getPassword(){
        return password;
    }

    public void setAuthCode(String authCode){
        this.authCode = authCode;
    }

    public String getAuthCode(){
        return authCode;
    }

    public float getCost(){
        return cost;
    }

    public int compareTo(Object object) {
        Resource another = (Resource)object;
        float distance = 0;
        
        if(ScheduleAlgorithm.compareFactor == CompareFactor.cost)
        	distance = another.getCost() - this.getCost();
        else
        	distance = another.getNextCompleteTime() - this.getNextCompleteTime();

        int result = 0;
        if(distance > 0 )
        {
            result = -1;
        }
        else if(distance < 0)
        {
            result = 1;
        }

        return result;
    }

	public int getJobsCounter() {
		return jobsCounter;
	}

	public String getHostName() {
		return hostName;
	}

	public String getAddress() {
		return address;
	}

	public int getPortNo() {
		return portNo;
	}

    public void clearNextCompleteTime(){
        this.nextCompleteTime = 0;
    }

	public ArrayList<Task> getTasks() {
		return tasks;
	}

	public int getFinishedJobs() {
		return finishedJobs;
	}
}
